﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ITAP.ShprossesBuilder.Editor;
using System.Drawing;
using ITAP.ShprossesBuilder.Modelling.Components;
using ITAP.ShprossesBuilder.Modelling;
using ITAP.ShprossesBuilder.Calculations;
using ITAP.Core.Modelling.Primitives;
using ITAP.ShprossesBuilder.Properties;
using ITAP.Core.Modelling;
using ITAP.Core.Calculations;

namespace ITAP.ShprossesBuilder.Operations
{
    public class OperationCreateShprossBarByShprossesVertical : IOperation
    {
        #region IOperation Members

        public string Name
        {
            get { return "Создать решётку с вертикальным основанием"; }
        }

        public OperationGroup OperationGroup
        {
            get { return OperationGroup.Other; }
        }

        public System.Drawing.Image Thumbnail
        {
            get { return Resources.CreateShprossBarVertical.ToBitmap(); }
        }

        public void Execute(ModelControl modelControl)
        {
            if (modelControl.ModelContainer.ActiveCell == null)
                return;

            SelectMaterialForm selectShprossForm = new SelectMaterialForm();
            selectShprossForm.Initialize(modelControl.ProfileProvider, new Material[] { Material.Shpross }, false, "Выберите профиль", false);
            if (selectShprossForm.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;

            Shpross shpross = selectShprossForm.SelectedComponent as Shpross;

            CreateShprossBarForm shprossBarForm = new CreateShprossBarForm();
            if (shprossBarForm.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;


            SnapOnCap snapOnCap = null;
            if (shprossBarForm.CreateSnapOnCaps)
            {
                SelectMaterialForm selectSnapOnCapForm = new SelectMaterialForm();
                selectSnapOnCapForm.Initialize(modelControl.ProfileProvider, new Material[] { Material.SnapOnCap }, false, "Выберите накладку", false);
                if (selectSnapOnCapForm.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                    return;
                snapOnCap = selectSnapOnCapForm.SelectedComponent as SnapOnCap;
            }

            RectangleF boundingBox = RectangleF.Empty;
            ModelCell activeCell = modelControl.ModelContainer.ActiveCell as ModelCell;
            ISpacer spacer = activeCell.Model.Spacer;
            switch (shprossBarForm.BarBorder)
            {
                case BarBorder.ByOuter:
                    boundingBox = activeCell.Model.BoundingBox;
                    break;
                case BarBorder.ByInner:
                    boundingBox = new RectangleF((float)(activeCell.Model.BoundingBox.X + spacer.SpacerWidth),
                                                 (float)(activeCell.Model.BoundingBox.Y + spacer.SpacerWidth),
                                                 (float)(activeCell.Model.BoundingBox.Width - 2 * spacer.SpacerWidth),
                                                 (float)(activeCell.Model.BoundingBox.Height - 2 * spacer.SpacerWidth));
                    break;
                case BarBorder.ByModelCell:
                    boundingBox = activeCell.BoundingBox;
                    break;

            }

            List<IComponent> components = this.CreateBarComponents(spacer, boundingBox, shpross, shprossBarForm.HorizontalCount, shprossBarForm.VerticalCount);



            foreach (IComponent component in components)
                activeCell.Model.AddInnerComponent(component);


            if (snapOnCap == null)
            {
                modelControl.UpdateModel();
                return;
            }

            modelControl.Manipulator.UpdateAllVisitors();
            modelControl.UpdateModel();

            List<StickConnector> stickConnectors = new List<StickConnector>();

            foreach (IComponent addedComponent in components)
            {
                if (addedComponent is Shpross)
                {
                    Shpross _shpross = addedComponent as Shpross;
                    if (_shpross.StartConnectedComponent is StickConnector)
                    {
                        stickConnectors.Add(_shpross.StartConnectedComponent as StickConnector);
                    }
                    if (_shpross.EndConnectedComponent is StickConnector)
                    {
                        stickConnectors.Add(_shpross.EndConnectedComponent as StickConnector);
                    }
                }
            }
            IEnumerable<StickConnector> distinct = stickConnectors.Distinct<StickConnector>(new StickConnectorComparer());


            foreach (StickConnector connector in distinct)
            {
                SnapOnCap clone = snapOnCap.Clone() as SnapOnCap;
                clone.MoveTo(connector.Position);
                connector.AddInnerComponent(clone);
            }

            modelControl.Manipulator.UpdateAllVisitors();

            modelControl.UpdateModel();
            modelControl.Manipulator.UpdateAllVisitors();

        }

        public bool CanUndo
        {
            get { return true; }
        }

        #endregion

        private List<IComponent> CreateBarComponents(ISpacer spacer, RectangleF boundingBox,
            Shpross shprossPrototype, int horizontalCount, int verticalCount)
        {
            List<IComponent> components = new List<IComponent>();
            components.AddRange(this.CreateHorizontalShprosses(spacer, boundingBox, shprossPrototype, horizontalCount, verticalCount));
            components.AddRange(this.CreateVerticalShprosses(spacer, boundingBox, shprossPrototype, horizontalCount, verticalCount));
            return components;
        }


        private List<IComponent> CreateVerticalShprosses(ISpacer spacer, RectangleF boundingBox,
            Shpross shprossPrototype, int horizontalCount, int verticalCount)
        {
            List<IComponent> components = new List<IComponent>();
            double horizontalOffset = boundingBox.Width / (horizontalCount + 1);
            double verticalOffset = boundingBox.Height / (verticalCount + 1);
            double x = boundingBox.X + horizontalOffset;
            double y = boundingBox.Y;

            ModelPoint prevVerticalPoint = new ModelPoint(x, y);
            List<IComponent> verticalShprosses = new List<IComponent>();
            for (int horizontal = 0; horizontal < horizontalCount; horizontal++)
            {
                verticalShprosses.Clear();
                prevVerticalPoint = new ModelPoint(x + horizontalOffset * horizontal, y);
                ModelPoint verticalPoint = new ModelPoint(x + horizontalOffset * horizontal,
                                                          y + boundingBox.Height);
                //if (!spacer.IsInSpacer(prevVerticalPoint) && !spacer.IsInSpacer(verticalPoint))
                //{
                //    continue;
                //}

                Shpross shpross = shprossPrototype.Clone() as Shpross;
                shpross.MoveStartPointTo(prevVerticalPoint);
                shpross.MoveEndPointTo(verticalPoint);
                if (shpross.StartSpacerConnector != null)
                {
                    shpross.FitStartSpacerConnector();
                    ConnectionProvider.Connect(shpross.StartConnectedComponent as IEndedComponent, spacer, EndType.Start);
                }

                if (shpross.EndSpacerConnector != null)
                {
                    shpross.FitEndSpacerConnector();
                    ConnectionProvider.Connect(shpross.EndConnectedComponent as IEndedComponent, spacer, EndType.Start);
                }
                components.Add(shpross);
            }
            return components;
        }

        private List<IComponent> CreateHorizontalShprosses(ISpacer spacer, RectangleF boundingBox,
            Shpross shprossPrototype, int horizontalCount, int verticalCount)
        {
            double shprossOffset = shprossPrototype.Width / 2;
            List<IComponent> components = new List<IComponent>();
            double horizontalOffset = boundingBox.Width / (horizontalCount + 1);
            double verticalOffset = boundingBox.Height / (verticalCount + 1);
            double x = boundingBox.X;
            double y = boundingBox.Y + verticalOffset;

            ModelPoint prevHorizontalPoint = new ModelPoint(x, y);
            List<IComponent> horizontalShprosses = new List<IComponent>();
            prevHorizontalPoint = ModelCalculations.GetOffsetPoint(prevHorizontalPoint, new ModelVector(shprossOffset, 0));
            for (int vertical = 0; vertical < verticalCount; vertical++)
            {
                horizontalShprosses.Clear();
                prevHorizontalPoint = new ModelPoint(x, y + verticalOffset * vertical);
                for (int horizontal = 1; horizontal <= horizontalCount + 1; horizontal++)
                {
                    ModelPoint connectorPoint = new ModelPoint(x + horizontalOffset * horizontal,
                                                              y + verticalOffset * vertical);
                    ModelPoint horizontalPoint = ModelCalculations.GetOffsetPoint(connectorPoint, new ModelVector(-shprossOffset, 0));
                    if (!spacer.IsInSpacer(prevHorizontalPoint) && !spacer.IsInSpacer(horizontalPoint))
                    {
                        continue;
                    }

                    Shpross shpross = shprossPrototype.Clone() as Shpross;
                    shpross.MoveStartPointTo(prevHorizontalPoint);
                    shpross.MoveEndPointTo(horizontalPoint);
                    prevHorizontalPoint = ModelCalculations.GetOffsetPoint(connectorPoint, new ModelVector(shprossOffset, 0));
                    horizontalShprosses.Add(shpross);
                }

                Shpross startShpross = horizontalShprosses[0] as Shpross;
                if (startShpross.StartSpacerConnector != null)
                {
                    startShpross.FitStartSpacerConnector();
                    ConnectionProvider.Connect(startShpross.StartConnectedComponent as IEndedComponent, spacer, EndType.Start);
                }

                Shpross endShpross = horizontalShprosses[horizontalShprosses.Count - 1] as Shpross;

                if (endShpross.EndSpacerConnector != null)
                {
                    endShpross.FitEndSpacerConnector();
                    ConnectionProvider.Connect(endShpross.EndConnectedComponent as IEndedComponent, spacer, EndType.Start);
                }

                components.AddRange(horizontalShprosses);
            }
            return components;
        }
    }
}
